(* Creme Caramel Compiler (Triple C) - Michele Caceffo - 2008 *)

open Exceptions;;
open Syntaxtree;;
open Intermediate;;
open Declaration;;
open Semantic;; (* LDL: this is becouse we will use one single function of this module, that is 'checkPexp' *)

(** Here are all the functions to generate the intermediate code for the arithmetical and boolean expressions *)

(** Creates the instructions for the parameters before a call
    @param plist The parameter list
    @param dect The declarations table
    @param proct The procedures table
    @param ic The instance of the intermediateCode instance
*)
(* LDL: adapt the function to the general idea of actual parameters *)
let rec genParam (plist: actual list) (dect: dec_table) (proct: proc_table) (tdtable: typedef_table) (ic: intermediateCode): unit = match plist with
        []      ->  ()
      | ParamAexp(a)::ae   ->  genParam ae dect proct tdtable ic; ic#addInstr (PARAM, (genArithmetical a dect proct tdtable ic), Null, Null)
      | ParamPexp(a)::ae   ->  genParam ae dect proct tdtable ic; ic#addInstr (PARAM, (genPointerExpr a dect proct ic), Null, Null)

(* LDL: we must have a function to deal with pointer expressions here *)
(** Creates the instruction for the pointer expressions 
    @param a The pointer expression to analize
    @param dect The declarations table
    @param proct The procedures table
    @param ic The intermediateCode class instance
    @return An element, which can be a Value, an Offset or a temporary register
*)
and genPointerExpr (p:pexp) (dect: dec_table) (proct: proc_table) (ic: intermediateCode): element = match p with
    PVar(ide)      ->  (
                        if (isVarDeclared ide dect) then (
                          let (_,_,stackoff) = getVarDeclaration ide dect in stackoff
                        ) else raise (NON_DECLARED_VARIABLE "ERROR: Undeclared variable")
                       )
  | Ref(PVar(ide)) ->  (* LDL: remember that @ can be only be applied to a variable in CCC, so we do not need recursion on v *)
                       (
		   	let reg = (ic#getReg) in (
		   	  let pexpr_gen = (genPointerExpr (PVar(ide)) dect proct ic) and stype = DPointer(checkPexp (PVar(ide)) dect (Some(proct))) in (
		   	    ic#addInstr(REF, pexpr_gen, Null, (Reg(reg,stype)));
		   	    (Reg(reg,stype))
		   	  )
		   	)
                       )
  | Ref(_)         ->  (* LDL: @ operator can only be applied on variables in CCC *)
                       let msg = "@ operator can only be applied on variables, " ^
		 	 "but this exception cannot be raised for parser structural reasons"
		       in raise (CONFIRM_RULE msg)  
  | Deref(pexpr)   ->  (* LDL: This rule is met for every ^ on the path and will eventually resolve
		           to a pointer variable (it is ensured by static semantics), case in
		           which we access the corresponding offset finding either another variable
		           or a sound value. We go back to the top until the chain ends.
		       *)
                       (
		   	let reg = (ic#getReg) in (
		   	  let pexpr_gen = (genPointerExpr pexpr dect proct ic) and stype = (checkPexp (Deref(pexpr)) dect (Some(proct))) in (
		   	    ic#addInstr(DEREF, pexpr_gen, Null, (Reg(reg,stype)));
		   	    (Reg(reg,stype))
		   	  )
		   	)
                       )
(** Creates the instruction for the arithmetical expressions 
    @param a The arithmetical expression to analize
    @param dect The declarations table
    @param proct The procedures table
    @param ic The intermediateCode class instance
    @return An element, which can be a Value, an Offset or a temporary register
*)
and genArithmetical (a:aexp) (dect: dec_table) (proct: proc_table) (tdtable: typedef_table) (ic: intermediateCode): element = match a with
    N(n)              ->  Val(I(n))
  | R(n)              ->  Val(F(n))
  | Ox(o)             ->  Val(O(o))  (* LDL: add the possibility to have a direct offset value *)
  | PNull             ->  Val(ONull) (* LDL: add the possibility to have a direct NULL offset *)
  | P(Deref(pexp))    ->  (* LDL: the semantics of a pointer P is to dereference the value of pexpr.*)
                          let off_register = genPointerExpr (Deref(pexp)) dect proct ic in off_register
  | P(_)              ->  (* LDL: If an arithmetical expression is formed by a pointer then it cannot be
			          either a reference pointer expression (i.e. an address)
			          nor a pointer variable (that is not arithmetical for sure)
			  *)
                          let msg = "Only dereferencing pointers can be there as arithmetical expressions." ^
			    "It is granted by design of the parser that this exception will never rise"
			  in raise (CONFIRM_RULE msg)  
  | Rec(Record(idel)) -> (* LDL: if a record is found as an arithmetical expression, traverse the corresponding 
			         tree and return the requested field (an offset)
			 *)
                         let rtree = getRTreeFromRecord (Record(idel)) dect tdtable and
			     (_,_,varoff) = let var = (List.hd idel) in
			                    if(isVarDeclared var dect) then (
					      getVarDeclaration var dect
					    ) else raise (NON_DECLARED_VARIABLE "ERROR: Undeclared variable")
			 in
			 (* LDL: the record_len return parameter is wildcarded here becouse this arithmetical
			         expression shows as a right expression. The left corresponding left expression
			         (that will be always as long as this for static semantics type checks) will
			         provide a way to scroll down the record in all its fields.
			 *)
			 let stackoff, _, _ = (traverseRTree rtree (List.tl idel) varoff) in stackoff
  | Var(i)            ->  (
                             if(isVarDeclared i dect) then (
                                let (_,_,stackoff) = getVarDeclaration i dect in stackoff
                             ) else raise (NON_DECLARED_VARIABLE "ERROR: Undeclared variable")
                          )
  | Vec(i,x)          ->  (
                           if(isVarDeclared i dect) then (
                              let xRes = genArithmetical x dect proct tdtable ic and
                              v = ic#getReg and
                              (_, _, stackoff) = getVecDeclaration i 0 (-1) dect in
                                let t = (match stackoff with
                                            Off(_, t, _) -> t
                                          | _ -> raise (CONFIRM_RULE "Cannot find something different from Off, as we already know we have an existing variable\n")
                                         )
                                in
				( (* LDL: we refactored and updated (wrt pointers) this piece of code *)
				  match t with
				      DInt | DFloat ->
					(
					  (ic#addInstr (AGET, stackoff, xRes, (Reg(v, t)));
					   (Reg(v, t)))
					)
				    | DPointer(_) -> let msg = "There cannot be pointers as values for vectors. " ^
						       "It is structurally impossible to get to this point."
						     in raise (CONFIRM_RULE msg)  
				    | _ -> raise (NON_DECLARED_VARIABLE "ERROR: Undeclared variable\n")
				)			       
			   ) else raise (NON_DECLARED_VARIABLE "ERROR: Undeclared variable")
                          )
  | Mat(i,x,y)        ->  (
                             if(isVarDeclared i dect) then (
                                let xRes = genArithmetical x dect proct tdtable ic and yRes = genArithmetical y dect proct tdtable ic and
                                r1,r2,r3 = (ic#getReg),(ic#getReg),(ic#getReg) and
                                (_, dim, stackoff) = getVecDeclaration i 0 0 dect in 
                                  let t = (match stackoff with
                                              Off(_, t, _) -> t
                                            | _ -> raise (CONFIRM_RULE "Cannot find something different from Off, as we already know we have an existing variable\n")
                                           )
                                  in
                                    (
                                    ic#addInstr (MUL, (Val(I(dim))), xRes, (Reg(r1,DInt)));
                                    ic#addInstr (ADD, (Reg(r1,DInt)), yRes, (Reg(r2,DInt)));
				    (* LDL: we refactored and updated (wrt pointers) this piece of code *)
				    match t with
					DInt | DFloat  ->
					  (
					    (ic#addInstr (AGET, stackoff, (Reg(r2, DInt)), (Reg(r3, t)));
					     (Reg(r3, t)))
					  )
				      | DPointer(_) -> let msg = "There cannot be pointers as values for matrices. " ^
							 "It is structurally impossible to get to this point."
						       in raise (CONFIRM_RULE msg)  

				      | _ -> raise (NON_DECLARED_VARIABLE "ERROR: Undeclared variable\n")				
                                    )				 
			     ) else raise (NON_DECLARED_VARIABLE "ERROR: Undeclared variable")
                           )
  | Sum(ex1,ex2)      ->  (
                             let reg = (ic#getReg) in (
                                let op1 = (genArithmetical ex1 dect proct tdtable ic)
                                and op2 = (genArithmetical ex2 dect proct tdtable ic)
                                in
                                let t = (match op1 with
                                            Off(_, t, _) -> t
                                          | Reg(_, t) -> t
                                          | Val(v) -> ( match v with
                                                           I(_) -> DInt
                                                         | F(_) -> DFloat
							 | O(_) | ONull -> let msg = "This happens when two pointer values are tried to be summed up. " ^
                                                                     "This is not allowed to sum up two pointers."
                                                                   in raise (SEMANTIC_ERROR msg)
                                                      )
                                          | _ -> raise (CONFIRM_RULE "We don't have any other operations")
                                         )
                                in (* We check the type for one of the two operands, as the semantic correctness has already been assessed *)
				( (* LDL: we refactored and updated (wrt pointers) this piece of code *)
				  match t with
				      DInt | DFloat ->
					(
					  (ic#addInstr(ADD, op1, op2,(Reg(reg, t)));
					   (Reg(reg, t)))
					)
				    | DPointer(_) -> let msg = "This happens when two pointers are tried to be summed up. " ^
						       "It is structurally impossible to get to this point."
						     in raise (CONFIRM_RULE msg)  
				    | DRecord(_) -> let msg = "This happens when two record types are tried to be summed up. " ^
						       "It is structurally impossible to get to this point."
						     in raise (CONFIRM_RULE msg)  
				    | _ -> raise (NON_DECLARED_VARIABLE "ERROR: Undeclared variable")
				)
			     )
                           )
    | Sub(ex1,ex2)      ->  (
                             let reg = (ic#getReg) in (
                                let op1 = (genArithmetical ex1 dect proct tdtable ic)
                                and op2 = (genArithmetical ex2 dect proct tdtable ic)
                                in
                                let t = (match op1 with
                                            Off(_, t, _) -> t
                                          | Reg(_, t) -> t
                                          | Val(v) -> ( match v with
                                                           I(_) -> DInt
                                                         | F(_) -> DFloat
							 | O(_) | ONull -> let msg = "This happens when two pointer values are tried to be subtracted. " ^
                                                                     "This is not allowed to subtract two pointers."
                                                                   in raise (SEMANTIC_ERROR msg)
                                                      )
                                          | _ -> raise (CONFIRM_RULE "We don't have any other operations")
                                         )
                                in (* We check the type for one of the two operands, as the semantic correctness has already been assessed *)
				( (* LDL: we refactored and updated (wrt pointers) this piece of code *)
				  match t with
				      DInt | DFloat ->
					(
					  (ic#addInstr(SUB, op1, op2,(Reg(reg, t)));
					   (Reg(reg, t)))
					)
				    | DPointer(_) -> let msg = "This happens when two pointers are tried to be subtracted. " ^
						       "It is structurally impossible to get to this point."
						     in raise (CONFIRM_RULE msg)  
				    | DRecord(_) -> let msg = "This happens when two record types are tried to be subtracted. " ^
						       "It is structurally impossible to get to this point."
						     in raise (CONFIRM_RULE msg)  
				    | _ -> raise (NON_DECLARED_VARIABLE "ERROR: Undeclared variable")
				)
			     )
                          )
  | Mul(ex1,ex2)      ->  (
                             let reg = (ic#getReg) in (
                                let op1 = (genArithmetical ex1 dect proct tdtable ic)
                                and op2 = (genArithmetical ex2 dect proct tdtable ic)
                                in
                                let t = (match op1 with
                                            Off(_, t, _) -> t
                                          | Reg(_, t) -> t
                                          | Val(v) -> ( match v with
                                                           I(_) -> DInt
                                                         | F(_) -> DFloat
							 | O(_) | ONull -> let msg = "This happens when two pointer values are tried to be multiplied. " ^
                                                                     "This is not allowed to multiply two pointers."
                                                                   in raise (SEMANTIC_ERROR msg)
                                                      )
                                          | _ -> raise (CONFIRM_RULE "We don't have any other operations")
                                         )
                                in (* We check the type for one of the two operands, as the semantic correctness has already been assessed *)
				( (* LDL: we refactored and updated (wrt pointers) this piece of code *)
				  match t with
				      DInt | DFloat ->
					(
					  (ic#addInstr(MUL, op1, op2,(Reg(reg, t)));
					   (Reg(reg, t)))
					)
				    | DPointer(_) -> let msg = "This happens when two pointers are tried to be multiplied. " ^
						    "It is structurally impossible to get to this point."
						  in raise (CONFIRM_RULE msg)  
				    | DRecord(_) -> let msg = "This happens when two record types are tried to be multiplied. " ^
						       "It is structurally impossible to get to this point."
						     in raise (CONFIRM_RULE msg)  
				    | _ -> raise (NON_DECLARED_VARIABLE "ERROR: Undeclared variable")
				)
			     )
                          )
  | Div(ex1,ex2)      ->  (
                             let reg = (ic#getReg) in (
                                let op1 = (genArithmetical ex1 dect proct tdtable ic)
                                and op2 = (genArithmetical ex2 dect proct tdtable ic)
                                in
                                let t = (match op1 with
                                            Off(_, t, _) -> t
                                          | Reg(_, t) -> t
                                          | Val(v) -> ( match v with
                                                           I(_) -> DInt
                                                         | F(_) -> DFloat
							 | O(_) | ONull -> let msg = "This happens when two pointer values are tried to be divided. " ^
                                                                     "This is not allowed to divide two pointers."
                                                                   in raise (SEMANTIC_ERROR msg)
                                                      )
                                          | _ -> raise (CONFIRM_RULE "We don't have any other operations")
                                         )
                                in (* We check the type for one of the two operands, as the semantic correctness has already been assessed *)
				( (* LDL: we refactored and updated (wrt pointers) this piece of code *)
				  match t with
				      DInt | DFloat ->
					(
					  (ic#addInstr(DIV, op1, op2,(Reg(reg, t)));
					   (Reg(reg, t)))
					)
				    | DPointer(_) -> let msg = "This happens when two pointers are tried to be divided. " ^
						    "It is structurally impossible to get to this point."
						  in raise (CONFIRM_RULE msg)  
				    | DRecord(_) -> let msg = "This happens when two record types are tried to be divided. " ^
						       "It is structurally impossible to get to this point."
						     in raise (CONFIRM_RULE msg)  
				    | _ -> raise (NON_DECLARED_VARIABLE "ERROR: Undeclared variable")
				)
			     )
                           )
    | FCall(Ide(i),plist)   ->  (
                                 let pten = (Hashtbl.find proct (Ide(i))) in match pten with
                                     Building(t, _)     ->  (
                                                                 let reg = (ic#getReg) in (
                                                                 (genParam plist dect proct tdtable ic);
                                                                 match t with 
                                                                    SRet(Int)   ->  ic#addInstr (CALL, Subr(i), Null, Reg(reg,DInt));
                                                                                    Reg(reg,DInt)
                                                                  | SRet(Float) ->  ic#addInstr (CALL, Subr(i), Null, Reg(reg,DFloat));
                                                                                    Reg(reg,DFloat)
                                                                  | SRet(UsrType(ut)) ->  (*let user_stype = (getSemanticUsrType ut tdtable) in
											   ic#addInstr (CALL, Subr(i), Null, Reg(reg,user_stype));
											   Reg(reg,user_stype)
											  *)
								                          raise (SEMANTIC_ERROR "Return values cannot be user defined types")
                                                                  | Void        ->  raise (SEMANTIC_ERROR "Void function")
                                                                 )
                                                                )
                                   | Subroutine(t,_,_,_)    ->  (
                                                                 let reg = (ic#getReg) in (
                                                                 (genParam plist dect proct tdtable ic);
                                                                 match t with 
                                                                    SRet(Int)   ->  ic#addInstr (CALL, Subr(i), Null, Reg(reg,DInt));
                                                                                    Reg(reg,DInt)
                                                                  | SRet(Float) ->  ic#addInstr (CALL, Subr(i), Null, Reg(reg,DFloat));
                                                                                    Reg(reg,DFloat)
                                                                  | SRet(UsrType(ut)) -> (*let user_stype = (getSemanticUsrType ut tdtable) in
											   ic#addInstr (CALL, Subr(i), Null, Reg(reg,user_stype));
											   Reg(reg,user_stype)
											 *)
								                          raise (SEMANTIC_ERROR "Return values cannot be user defined types")
                                                                  | Void        ->  raise (SEMANTIC_ERROR "Void function")
                                                                 )
                                                                )
                                )
(** Creates the instruction for the boolean expressions 
    @param a The boolean expression to analize
    @param dect The declarations table
    @param proct The procedures table
    @param ic The intermediateCode class instance
    @return An element, which can be a Value or a temporary register
*)
let rec genBoolean (a: bexp) (dect: dec_table) (proct: proc_table) (tdtable: typedef_table) (ic: intermediateCode): element = match a with
    B(b)              ->  if b then (Val(I(1))) else (Val(I(0)))
  | Equ(ex1,ex2)      ->  (* LDL: check if the expressions are records and in the case handle the situation *)
                          (match ex1,ex2 with
			      Rec(Record(idel1)), Rec(Record(idel2)) -> 
				let (t1,t2, record_len, typelist) = (* LDL: note that record_len and typelist are the same *)
				  (* LDL: if a record is found as an arithmetical expression, traverse the corresponding 
			                  tree and return the requested field (an offset)
				  *)
				  let rtree1 = getRTreeFromRecord (Record(idel1)) dect tdtable and
				      rtree2 = getRTreeFromRecord (Record(idel2)) dect tdtable and
				      (_,_,varoff1) = let var = (List.hd idel1) in
						      if(isVarDeclared var dect) then (
							getVarDeclaration var dect
						      ) else raise (NON_DECLARED_VARIABLE "ERROR: Undeclared variable")
				  and (_,_,varoff2) = let var = (List.hd idel2) in
						      if(isVarDeclared var dect) then (
							getVarDeclaration var dect
						      ) else raise (NON_DECLARED_VARIABLE "ERROR: Undeclared variable")
				  in
				  (* LDL: the record_len return parameter is wildcarded here becouse this arithmetical
			                  expression shows as a right expression. The left corresponding left expression
			                  (that will be always as long as this for static semantics type checks) will
			                  provide a way to scroll down the record in all its fields.
				  *)
				  let stackoff1, record_len1, typelist1 = (traverseRTree rtree1 (List.tl idel1) varoff1)
				  and stackoff2, record_len2, typelist2 = (traverseRTree rtree2 (List.tl idel2) varoff2)
				  in stackoff1, stackoff2, record_len1, typelist1
				in
				let rec pipe_conditions t1 t2 typelist reg_so_far i =
				  match i with
				      -1 -> reg_so_far
				    | _  -> let off1,b1, off2,b2 =
					      match t1, t2 with
						  Off(off1, _, b1), Off(off2, _, b2) -> off1, b1, off2, b2
					        | _ -> let msg = "Here is not possible to have something different from an offset"
						       in raise (CONFIRM_RULE msg)
					    in
					    let augmented_stackoff1 = Off(off1+i, (List.nth typelist i), b1)
					    and augmented_stackoff2 = Off(off2+i, (List.nth typelist i), b2)
					    and reg = (ic#getReg) and new_reg = (ic#getReg)
					    in
					    ic#addInstr(CEQU, augmented_stackoff1, augmented_stackoff2, (Reg(reg,DInt)));
					    ic#addInstr(AND, (Reg(reg,DInt)), reg_so_far, (Reg(new_reg,DInt)));
					    pipe_conditions t1 t2 typelist (Reg(new_reg,DInt)) (i-1)
				in
				let reg = ic#getReg in
				let reg_true = ic#addInstr(CPY, Val(I(1)), Null, (Reg(reg,DInt))); Reg(reg,DInt) in
				pipe_conditions t1 t2 typelist reg_true (record_len-1)
			    | _ ->  let reg = (ic#getReg) and 
				    (t1,t2) = (genArithmetical ex1 dect proct tdtable ic),(genArithmetical ex2 dect proct tdtable ic) in (
                                      ic#addInstr(CEQU, t1, t2, (Reg(reg,DInt)));
                                      (Reg(reg,DInt))
				     )                               
			  )
  | LE(ex1,ex2)       ->  (* LDL: check if the expressions are records and in the case handle the situation *)
                          (match ex1,ex2 with
			      Rec(Record(idel1)), Rec(Record(idel2)) -> 
				let (t1,t2, record_len, typelist) = (* LDL: note that record_len and typelist are the same *)
				  (* LDL: if a record is found as an arithmetical expression, traverse the corresponding 
			                  tree and return the requested field (an offset)
				  *)
				  let rtree1 = getRTreeFromRecord (Record(idel1)) dect tdtable and
				      rtree2 = getRTreeFromRecord (Record(idel2)) dect tdtable and
				      (_,_,varoff1) = let var = (List.hd idel1) in
						      if(isVarDeclared var dect) then (
							getVarDeclaration var dect
						      ) else raise (NON_DECLARED_VARIABLE "ERROR: Undeclared variable")
				  and (_,_,varoff2) = let var = (List.hd idel2) in
						      if(isVarDeclared var dect) then (
							getVarDeclaration var dect
						      ) else raise (NON_DECLARED_VARIABLE "ERROR: Undeclared variable")
				  in
				  (* LDL: the record_len return parameter is wildcarded here becouse this arithmetical
			                  expression shows as a right expression. The left corresponding left expression
			                  (that will be always as long as this for static semantics type checks) will
			                  provide a way to scroll down the record in all its fields.
				  *)
				  let stackoff1, record_len1, typelist1 = (traverseRTree rtree1 (List.tl idel1) varoff1)
				  and stackoff2, record_len2, typelist2 = (traverseRTree rtree2 (List.tl idel2) varoff2)
				  in stackoff1, stackoff2, record_len1, typelist1
				in
				let rec pipe_conditions t1 t2 typelist reg_so_far i =
				  match i with
				      -1 -> reg_so_far
				    | _  -> let off1,b1, off2,b2 =
					      match t1, t2 with
						  Off(off1, _, b1), Off(off2, _, b2) -> off1, b1, off2, b2
					        | _ -> let msg = "Here is not possible to have something different from an offset"
						       in raise (CONFIRM_RULE msg)
					    in
					    let augmented_stackoff1 = Off(off1+i, (List.nth typelist i), b1)
					    and augmented_stackoff2 = Off(off2+i, (List.nth typelist i), b2)
					    and reg = (ic#getReg) and new_reg = (ic#getReg)
					    in
					    ic#addInstr(CGE, augmented_stackoff1, augmented_stackoff2, (Reg(reg,DInt)));
					    ic#addInstr(AND, (Reg(reg,DInt)), reg_so_far, (Reg(new_reg,DInt)));
					    pipe_conditions t1 t2 typelist (Reg(new_reg,DInt)) (i-1)
				in
				let reg = ic#getReg in
				let reg_true = ic#addInstr(CPY, Val(I(1)), Null, (Reg(reg,DInt))); Reg(reg,DInt) in
				pipe_conditions t1 t2 typelist reg_true (record_len-1)
			    | _ ->  let reg = (ic#getReg) and 
				(t1,t2) = (genArithmetical ex1 dect proct tdtable ic),(genArithmetical ex2 dect proct tdtable ic) in (
                                  ic#addInstr(CGE, t2, t1, (Reg(reg,DInt)));
                                  (Reg(reg,DInt))
				 )
                            )
  | LT(ex1,ex2)       ->  (* LDL: check if the expressions are records and in the case handle the situation *)
                          (match ex1,ex2 with
			      Rec(Record(idel1)), Rec(Record(idel2)) -> 
				let (t1,t2, record_len, typelist) = (* LDL: note that record_len and typelist are the same *)
				  (* LDL: if a record is found as an arithmetical expression, traverse the corresponding 
			                  tree and return the requested field (an offset)
				  *)
				  let rtree1 = getRTreeFromRecord (Record(idel1)) dect tdtable and
				      rtree2 = getRTreeFromRecord (Record(idel2)) dect tdtable and
				      (_,_,varoff1) = let var = (List.hd idel1) in
						      if(isVarDeclared var dect) then (
							getVarDeclaration var dect
						      ) else raise (NON_DECLARED_VARIABLE "ERROR: Undeclared variable")
				  and (_,_,varoff2) = let var = (List.hd idel2) in
						      if(isVarDeclared var dect) then (
							getVarDeclaration var dect
						      ) else raise (NON_DECLARED_VARIABLE "ERROR: Undeclared variable")
				  in
				  (* LDL: the record_len return parameter is wildcarded here becouse this arithmetical
			                  expression shows as a right expression. The left corresponding left expression
			                  (that will be always as long as this for static semantics type checks) will
			                  provide a way to scroll down the record in all its fields.
				  *)
				  let stackoff1, record_len1, typelist1 = (traverseRTree rtree1 (List.tl idel1) varoff1)
				  and stackoff2, record_len2, typelist2 = (traverseRTree rtree2 (List.tl idel2) varoff2)
				  in stackoff1, stackoff2, record_len1, typelist1
				in
				let rec pipe_conditions t1 t2 typelist reg_so_far i =
				  match i with
				      -1 -> reg_so_far
				    | _  -> let off1,b1, off2,b2 =
					      match t1, t2 with
						  Off(off1, _, b1), Off(off2, _, b2) -> off1, b1, off2, b2
					        | _ -> let msg = "Here is not possible to have something different from an offset"
						       in raise (CONFIRM_RULE msg)
					    in
					    let augmented_stackoff1 = Off(off1+i, (List.nth typelist i), b1)
					    and augmented_stackoff2 = Off(off2+i, (List.nth typelist i), b2)
					    and reg = (ic#getReg) and new_reg = (ic#getReg)
					    in
					    ic#addInstr(CG, augmented_stackoff1, augmented_stackoff2, (Reg(reg,DInt)));
					    ic#addInstr(AND, (Reg(reg,DInt)), reg_so_far, (Reg(new_reg,DInt)));
					    pipe_conditions t1 t2 typelist (Reg(new_reg,DInt)) (i-1)
				in
				let reg = ic#getReg in
				let reg_true = ic#addInstr(CPY, Val(I(1)), Null, (Reg(reg,DInt))); Reg(reg,DInt) in
				pipe_conditions t1 t2 typelist reg_true (record_len-1)
			    | _ ->  let reg = (ic#getReg) and 
                             (t1,t2) = (genArithmetical ex1 dect proct tdtable ic),(genArithmetical ex2 dect proct tdtable ic) in (
                                 ic#addInstr(CG, t2, t1, (Reg(reg,DInt)));
                                 (Reg(reg,DInt))
                             )
                            )
  | Not(b)            ->  (
                             let reg = (ic#getReg) in (
                                 ic#addInstr(NOT, (genBoolean b dect proct tdtable ic), Null, (Reg(reg,DInt)));
                                 (Reg(reg,DInt))
                             )
                            )
  | And(bex1,bex2)    ->  (
                             let reg = (ic#getReg) in (
                                 ic#addInstr(AND, (genBoolean bex1 dect proct tdtable ic), (genBoolean bex2 dect proct tdtable ic), (Reg(reg,DInt)));
                                 (Reg(reg,DInt))
                             )
                            )
  | Or(bex1,bex2)     ->  (
                             let reg = (ic#getReg) in (
                                 ic#addInstr(OR, (genBoolean bex1 dect proct tdtable ic), (genBoolean bex2 dect proct tdtable ic), (Reg(reg,DInt)));
                                 (Reg(reg,DInt))
                             )
                            )
